package com.example.controller.feign;

import com.example.config.ItemClientFeign;
import io.swagger.annotations.ApiOperation;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@Order(value = 1)   //顺序，自小而大执行
public class InterfaceRecordApplication implements ApplicationContextAware, CommandLineRunner {

    @Value("${web.module}")
    private String moduleName;

    private static ApplicationContext context;

    @Autowired
    private ItemClientFeign service;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    @Override
    public void run(String... args) throws Exception {
        //获取使用RestController注解标注的所有Controller类
        Map<String, Object> controllers = context.getBeansWithAnnotation(RestController.class);
        List<Map<String, List<String>>> apiOperationList = new ArrayList<>();
        //遍历每个controller层
        for (Map.Entry<String, Object> entry : controllers.entrySet()) {
            Object value = entry.getValue();
            Class<?> aClass = AopUtils.getTargetClass(value);
            Map<String, List<String>> apiOperation = getApiOperation(aClass);
            apiOperationList.add(apiOperation);
        }
        System.out.println("模块【" + moduleName + "】即将写入接口信息");
        try {
            //测试跨服务调用是否正常，正常返回：【得到回应：测试信号】
            System.out.println(service.echo("测试信号"));
            //正式写入接口
            service.refreshModuleInterfaceRecords(moduleName, apiOperationList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("模块【" + moduleName + "】写入接口信息完毕");
    }

    //根据类和url关键字获取指定ApiOperation描述
    private Map<String, List<String>> getApiOperation(Class aClass){
        Map<String,List<String>> map = new HashMap<>();
        if(null == aClass){
            return map;
        }
        String classUrl = "";
        RequestMapping classAnnotation = (RequestMapping) aClass.getAnnotation(RequestMapping.class);
        if (null != classAnnotation){
            classUrl = classAnnotation.value()[0];
        }
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            String methodUrl = null;
            RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
            if (null != requestMapping){
                methodUrl = requestMapping.value()[0];
            }
            GetMapping getMapping = method.getAnnotation(GetMapping.class);
            if (null != getMapping){
                methodUrl = getMapping.value()[0];
            }
            PostMapping postMapping = method.getAnnotation(PostMapping.class);
            if (null != postMapping){
                methodUrl = postMapping.value()[0];
            }
            DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
            if (null != deleteMapping){
                methodUrl = deleteMapping.value()[0];
            }
            PutMapping putMapping = method.getAnnotation(PutMapping.class);
            if (null != putMapping){
                methodUrl = putMapping.value()[0];
            }
            if (null == methodUrl){
                continue;
            }
            try {
                ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
                if (null != apiOperation){
                    List<String> operations = new ArrayList<>();
                    operations.add(apiOperation.value());
                    operations.add(apiOperation.notes());
                    map.put(classUrl + methodUrl, operations);
                } else {
                    List<String> operations = new ArrayList<>();
                    operations.add("缺省");
                    operations.add("缺省");
                    map.put(classUrl + methodUrl, operations);
                }
            } catch (Exception e) {
                List<String> operations = new ArrayList<>();
                operations.add("缺省");
                operations.add("缺省");
                map.put(classUrl + methodUrl, operations);
            }
        }
        return map;
    }
}
